module mask_ram_1rw #(
    parameter DW = 32,
    parameter AW = 4,
    parameter INIT_RAM = 0,
    parameter INIT_FILE = ""
) (
    input           clk,
    input           cs,
    input           we,
    input  [DW-1:0] wmask,
    input  [AW-1:0] addr,
    input  [DW-1:0] wdata,
    output [DW-1:0] rdata
);

  localparam DEPTH = 2 ** AW;
  logic [DW-1:0] mem[0:DEPTH-1];

  initial if (INIT_RAM) $readmemh(INIT_FILE, mem);

  logic [DW-1:0] rdata_r;

  always_ff @(posedge clk) begin
    if (cs) begin
      if (we) mem[addr] <= (mem[addr] & (~wmask)) | (wdata & wmask);
      else rdata_r <= mem[addr];
    end
  end

  assign rdata = rdata_r;

endmodule

module ram_1rw #(
    parameter DW = 32,
    parameter AW = 4
) (
    input           clk,
    input           cs,
    input           we,
    input  [AW-1:0] addr,
    input  [DW-1:0] wdata,
    output [DW-1:0] rdata
);

  localparam DEPTH = 2 ** AW;
  logic [DW-1:0] mem[0:DEPTH-1];

  logic [DW-1:0] rdata_r;

  always_ff @(posedge clk) begin
    if (cs) begin
      if (we) mem[addr] <= wdata;
      else rdata_r <= mem[addr];
    end
  end

  assign rdata = rdata_r;

endmodule

module mask_ram_1r_1w #(
    parameter DW = 32,
    parameter AW = 4
) (
    input           clk,
    input           cs,
    input           we,
    input  [DW-1:0] wmask,
    input  [AW-1:0] waddr,
    input  [DW-1:0] wdata,
    input           re,
    input  [AW-1:0] raddr,
    output [DW-1:0] rdata
);

  localparam DEPTH = 2 ** AW;
  logic [DW-1:0] mem[0:DEPTH-1];

  logic [DW-1:0] rdata_r;

  always_ff @(posedge clk) begin
    if (cs & we) mem[waddr] <= (mem[waddr] & (~wmask)) | (wdata & wmask);
    if (cs & re) rdata_r <= mem[raddr];
  end

  assign rdata = rdata_r;

endmodule

module ram_1r_1w #(
    parameter DW = 32,
    parameter AW = 4
) (
    input           clk,
    input           cs,
    input           we,
    input  [AW-1:0] waddr,
    input  [DW-1:0] wdata,
    input           re,
    input  [AW-1:0] raddr,
    output [DW-1:0] rdata
);

  localparam DEPTH = 2 ** AW;
  logic [DW-1:0] mem[0:DEPTH-1];

  logic [DW-1:0] rdata_r;

  always_ff @(posedge clk) begin
    if (cs & we) mem[waddr] <= wdata;
    if (cs & re) rdata_r <= mem[raddr];
  end

  assign rdata = rdata_r;

endmodule
